<template>
  <!-- 预览弹窗 -->
  <div class="preview-modal" v-if="visible" @click="handleClose">
    <div class="preview-content" @click.stop>
      <!-- 图片预览 -->
      <div v-if="previewType === 'image'" class="image-preview">
        <div class="preview-header">
          <span class="preview-title">图片预览</span>
          <div class="image-controls">
            <button class="control-btn" @click="zoomOut" title="缩小 (-)">-</button>
            <span class="zoom-level">{{ Math.round(imageScale * 100) }}%</span>
            <button class="control-btn" @click="zoomIn" title="放大 (+)">+</button>
            <button class="control-btn" @click="resetImageView" title="重置 (0)">⟲</button>
          </div>
          <button class="close-btn" @click="handleClose">×</button>
        </div>
        <div
          class="image-container"
          ref="imageContainer"
          @wheel="handleWheel"
          @mousedown="handleMouseDown"
        >
          <img
            :src="previewUrl"
            alt="预览图片"
            class="preview-image"
            :style="{
              transform: `scale(${imageScale}) translate(${imagePosition.x}px, ${imagePosition.y}px)`,
              cursor: isDragging ? 'grabbing' : 'grab',
            }"
            @dragstart.prevent
          />
        </div>
        <div class="image-tips">
          <span>提示：滚轮缩放 | 拖拽移动 | 快捷键：+ 放大，- 缩小，0 重置</span>
        </div>
      </div>

      <!-- 文件预览 -->
      <div v-else-if="previewType === 'file'" class="file-preview">
        <div class="preview-header">
          <span class="preview-title">{{ fileName }}</span>
          <div class="file-controls">
            <span class="file-tip">支持 PDF、Word、Excel、PowerPoint 等格式在线预览</span>
          </div>
          <button class="close-btn" @click="handleClose">×</button>
        </div>
        <div class="file-container">
          <!-- 加载状态 -->
          <div v-if="fileLoading" class="file-loading">
            <div class="loading-spinner"></div>
            <div class="loading-text">正在加载文件预览...</div>
          </div>

          <!-- 错误状态 -->
          <div v-else-if="fileError" class="file-error">
            <div class="error-icon">⚠️</div>
            <div class="error-text">文件预览失败</div>
            <div class="error-tips">请检查文件格式是否支持或网络连接是否正常</div>
            <button class="retry-btn" @click="retryPreview">重试</button>
          </div>

          <!-- 文件预览iframe -->
          <iframe
            v-else
            :src="previewUrl"
            class="preview-iframe"
            frameborder="0"
            loading="lazy"
            @load="onFileLoad"
            @error="onFileError"
          ></iframe>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue'

// Props
const props = defineProps({
  visible: {
    type: Boolean,
    default: false,
  },
  type: {
    type: String,
    default: '', // 'image' 或 'file'
    validator: (value) => ['', 'image', 'file'].includes(value),
  },
  url: {
    type: String,
    default: '',
  },
  fileName: {
    type: String,
    default: '',
  },
})

// Emits
const emit = defineEmits(['close', 'retry'])

// 响应式数据
const previewType = ref('')
const previewUrl = ref('')

// 图片预览相关
const imageScale = ref(1)
const imagePosition = ref({ x: 0, y: 0 })
const isDragging = ref(false)
const dragStart = ref({ x: 0, y: 0 })
const imageContainer = ref(null)

// 文件预览相关
const fileLoading = ref(false)
const fileError = ref(false)

// 方法
const handleClose = () => {
  emit('close')
  resetState()
}

const resetState = () => {
  // 重置图片状态
  imageScale.value = 1
  imagePosition.value = { x: 0, y: 0 }
  isDragging.value = false
  // 重置文件状态
  fileLoading.value = false
  fileError.value = false
}

const retryPreview = () => {
  emit('retry')
}

// 图片缩放和拖拽功能
const handleWheel = (event) => {
  if (previewType.value !== 'image') return

  event.preventDefault()
  const delta = event.deltaY > 0 ? -0.1 : 0.1
  const newScale = Math.max(0.1, Math.min(5, imageScale.value + delta))
  imageScale.value = newScale
}

const handleMouseDown = (event) => {
  if (previewType.value !== 'image') return

  isDragging.value = true
  dragStart.value = {
    x: event.clientX - imagePosition.value.x,
    y: event.clientY - imagePosition.value.y,
  }
}

const handleMouseMove = (event) => {
  if (!isDragging.value || previewType.value !== 'image') return

  imagePosition.value = {
    x: event.clientX - dragStart.value.x,
    y: event.clientY - dragStart.value.y,
  }
}

const handleMouseUp = () => {
  isDragging.value = false
}

const resetImageView = () => {
  imageScale.value = 1
  imagePosition.value = { x: 0, y: 0 }
}

const zoomIn = () => {
  imageScale.value = Math.min(5, imageScale.value + 0.2)
}

const zoomOut = () => {
  imageScale.value = Math.max(0.1, imageScale.value - 0.2)
}

const onFileLoad = () => {
  fileLoading.value = false
}

const onFileError = () => {
  fileLoading.value = false
  fileError.value = true
}

// 键盘事件处理
const handleKeydown = (event) => {
  if (!props.visible) return

  if (event.key === 'Escape') {
    handleClose()
  }
  if (previewType.value === 'image') {
    if (event.key === '=' || event.key === '+') {
      zoomIn()
    } else if (event.key === '-') {
      zoomOut()
    } else if (event.key === '0') {
      resetImageView()
    }
  }
}

// 监听 props 变化
watch(
  () => props.visible,
  (newVal) => {
    if (newVal) {
      previewType.value = props.type
      previewUrl.value = props.url
    } else {
      resetState()
    }
  },
)

// 生命周期
onMounted(() => {
  document.addEventListener('keydown', handleKeydown)
  document.addEventListener('mousemove', handleMouseMove)
  document.addEventListener('mouseup', handleMouseUp)
})

onUnmounted(() => {
  document.removeEventListener('keydown', handleKeydown)
  document.removeEventListener('mousemove', handleMouseMove)
  document.removeEventListener('mouseup', handleMouseUp)
})
</script>

<style scoped lang="scss">
// 预览弹窗样式
.preview-modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;

  .preview-content {
    position: relative;
    background: white;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0px 20px 40px rgba(0, 0, 0, 0.3);
    max-width: 90vw;
    max-height: 90vh;

    .preview-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 16px 20px;
      background: #f8f9fa;
      border-bottom: 1px solid #e5e5e5;

      .preview-title {
        font-family: PingFang SC;
        font-weight: 500;
        font-size: 16px;
        color: #323333;
      }

      .image-controls {
        display: flex;
        align-items: center;
        gap: 8px;

        .control-btn {
          width: 32px;
          height: 32px;
          border: 1px solid #ddd;
          background: white;
          color: #666;
          border-radius: 4px;
          cursor: pointer;
          font-size: 16px;
          display: flex;
          align-items: center;
          justify-content: center;
          transition: all 0.3s ease;

          &:hover {
            background: #f0f0f0;
            border-color: #999;
          }
        }

        .zoom-level {
          font-family: PingFang SC;
          font-weight: 500;
          font-size: 14px;
          color: #666;
          min-width: 50px;
          text-align: center;
        }
      }

      .file-controls {
        .file-tip {
          font-family: PingFang SC;
          font-weight: 400;
          font-size: 12px;
          color: #999;
        }
      }

      .close-btn {
        width: 32px;
        height: 32px;
        border: none;
        background: #e74c3c;
        color: white;
        border-radius: 50%;
        cursor: pointer;
        font-size: 20px;
        line-height: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: all 0.3s ease;

        &:hover {
          background: #c0392b;
          transform: scale(1.1);
        }
      }
    }

    .image-preview {
      .image-container {
        width: 80vw;
        height: 70vh;
        overflow: hidden;
        display: flex;
        align-items: center;
        justify-content: center;
        background: #f8f9fa;
        position: relative;

        .preview-image {
          max-width: none;
          max-height: none;
          object-fit: contain;
          border-radius: 8px;
          box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.2);
          transition: transform 0.1s ease;
          user-select: none;
        }
      }

      .image-tips {
        padding: 12px 20px;
        background: #f8f9fa;
        border-top: 1px solid #e5e5e5;
        text-align: center;

        span {
          font-family: PingFang SC;
          font-weight: 400;
          font-size: 12px;
          color: #999;
        }
      }
    }

    .file-preview {
      width: 85vw;
      height: 85vh;

      .file-container {
        height: calc(85vh - 65px);
        position: relative;

        .preview-iframe {
          width: 100%;
          height: 100%;
          border: none;
        }

        .file-loading {
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          height: 100%;
          background: #f8f9fa;

          .loading-spinner {
            width: 40px;
            height: 40px;
            border: 4px solid #e3e3e3;
            border-top: 4px solid #38d3c3;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin-bottom: 16px;
          }

          .loading-text {
            font-family: PingFang SC;
            font-weight: 400;
            font-size: 16px;
            color: #666;
          }
        }

        .file-error {
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          height: 100%;
          background: #f8f9fa;
          gap: 12px;

          .error-icon {
            font-size: 48px;
          }

          .error-text {
            font-family: PingFang SC;
            font-weight: 500;
            font-size: 18px;
            color: #e74c3c;
          }

          .error-tips {
            font-family: PingFang SC;
            font-weight: 400;
            font-size: 14px;
            color: #999;
            text-align: center;
            max-width: 400px;
          }

          .retry-btn {
            padding: 8px 16px;
            background: #38d3c3;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-family: PingFang SC;
            font-weight: 500;
            font-size: 14px;
            transition: all 0.3s ease;

            &:hover {
              background: #2bc1b1;
            }
          }
        }
      }
    }

    @keyframes spin {
      0% {
        transform: rotate(0deg);
      }
      100% {
        transform: rotate(360deg);
      }
    }
  }
}
</style>
